package com.tbit.main.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.tbit.main.h2.pojo.ParkPoint;
import com.tbit.main.pojo.*;
import com.tbit.main.service.*;
import com.tbit.main.util.DateTimeUtil;
import com.tbit.main.util.GeoUtil;
import com.tbit.main.util.ListUtil;
import com.tbit.main.util.LogUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author LMY
 * @create 2021-06-29 19:33
 */
@Slf4j
@Service("georeQuartzService")
public class GeoreQuartzServiceImpl implements GeoreQuartzService {

    @Autowired
    private GeoreGionService georeGionService;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private GeoreMachineService georeMachineService;
    @Autowired
    private DataService dataService;
    @Autowired
    private ParkPointService parkPointService;
    @Autowired
    private ProhibitAreaService prohibitAreaService;
    @Autowired
    private MachineService machineService;
    @Autowired
    private AccountEventService accountEventService;

    @Override
    //@Scheduled(cron = "0 1/5 * * * ?")
    public void updateMachineGeo() {

        LogUtil.info("分区车辆更新定时任务！");
        long t1 = System.currentTimeMillis();

        //分区数据
        Map<Integer, List<Integer>> accountGeoMapTemp = new HashMap<>();
        Map<Integer, List<Point>> geoRegionMapTemp = new HashMap<>();
        List<GeoreGion> georeGions = georeGionService.getAll();
        for (GeoreGion georeGion : georeGions) {
            try {
                geoRegionMapTemp.put(georeGion.getRegionId(), GeoUtil.getPoints(georeGion.getPoints()));
                if (accountGeoMapTemp.containsKey(georeGion.getAccountId())) {
                    accountGeoMapTemp.get(georeGion.getAccountId()).add(georeGion.getRegionId());
                } else {
                    List<Integer> regionIds = new LinkedList<>();
                    regionIds.add(georeGion.getRegionId());
                    accountGeoMapTemp.put(georeGion.getAccountId(), regionIds);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                LogUtil.info(e.toString());
            }
        }

        /**删除无车辆分区*/
        List<Integer> regionIds = georeMachineService.getNotRegionId();
        if (regionIds != null && regionIds.size() > 0) {
            georeMachineService.deleteRegionId(regionIds);
        }

        /**删除无状态车辆分区*/
        List<Integer> machineIdStatus = georeMachineService.getNotStatus();
        if (machineIdStatus != null && machineIdStatus.size() > 0) {
            georeMachineService.deleteStatus(machineIdStatus);
        }

        //获取更新分区 区域
        List<Integer> accountUpdate = georeGionService.getAccountIdUpdate(DateTimeUtil.getNowTimeBefore(-10));

        //获取所有区域
        List<Integer> accountIds = georeGionService.getAccountId();
        accountIds = ListUtil.getSameIntegerList(accountIds, accountUpdate);

        if (accountIds != null && accountIds.size() > 0) {
            /**获取分区车辆状态*/
            List<MachineStatus> machineStatusList = machineStatusService.getAccountIdsPosDt(accountIds, DateTimeUtil.getNowTimeBefore(-10));

            /**获取未分区车辆状态*/
            machineStatusList.addAll(machineStatusService.getAccountIdNotRegionId(accountIds, DateTimeUtil.getNowTimeBefore(-10)));

            if (accountUpdate != null && accountUpdate.size() > 0) {
                machineStatusList.addAll(machineStatusService.getAccountIdsPosDt(accountUpdate, null));
            }

            /**获取分区车辆*/
            List<Integer> machineIds = machineStatusList.stream().map(MachineStatus::getMachineId).collect(Collectors.toList());
            machineIds = machineIds.stream().filter(e -> e != null).collect(Collectors.toList());
            Map<Integer, Integer> georeMachineMap = new HashMap<>();
            if (machineIds != null && machineIds.size() > 0) {
                List<GeoreMachine> georeMachines = georeMachineService.getByMachineIds(machineIds);
                for (GeoreMachine georeMachine : georeMachines) {
                    georeMachineMap.put(georeMachine.getMachineId(), georeMachine.getRegionId());
                }
            }

            /**拼接车辆状态*/
            Map<Integer, List<MachineStatus>> statusList = new HashMap<>();
            for (MachineStatus machineStatus : machineStatusList) {
                if (statusList.containsKey(machineStatus.getAccountId())) {
                    statusList.get(machineStatus.getAccountId()).add(machineStatus);
                } else {
                    List<MachineStatus> machineStatuses = new LinkedList<>();
                    machineStatuses.add(machineStatus);
                    statusList.put(machineStatus.getAccountId(), machineStatuses);
                }
            }

            List<GeoreMachine> georeMachinesUpdate = new LinkedList<>();
            List<GeoreMachine> georeMachinesInsert = new LinkedList<>();
            for (Integer key : statusList.keySet()) {
                for (MachineStatus machineStatus : statusList.get(key)) {
                    boolean exist = true;
                    Point point = new Point();
                    point.setX(machineStatus.getLon());
                    point.setY(machineStatus.getLat());
                    for (Integer regionId : accountGeoMapTemp.get(machineStatus.getAccountId())) {
                        /**在分区内的*/
                        if (geoRegionMapTemp.get(regionId) == null) {
                            break;
                        }
                        if (GeoUtil.IsPtInPoly(point, geoRegionMapTemp.get(regionId))) {
                            exist = false;
                            GeoreMachine georeMachine = new GeoreMachine();
                            georeMachine.setRegionId(regionId);
                            georeMachine.setAccountId(key);
                            georeMachine.setMachineId(machineStatus.getMachineId());
                            if (georeMachineMap.containsKey(machineStatus.getMachineId())) {
                                if (!georeMachineMap.get(machineStatus.getMachineId()).equals(regionId)) {
                                    georeMachine.setBeforeRegionId(georeMachineMap.get(machineStatus.getMachineId()));
                                    georeMachine.setUpdateTime(DateTimeUtil.getNowTime());
                                    georeMachinesUpdate.add(georeMachine);
                                }
                            } else {
                                georeMachine.setAddTime(DateTimeUtil.getNowTime());
                                georeMachinesInsert.add(georeMachine);
                            }
                            break;
                        }
                    }

                    /**不在所有分区内*/
                    if (exist) {
                        Map<Double, Integer> minDistance = new TreeMap<>(new Comparator<Double>() {
                            public int compare(Double obj1, Double obj2) {
                                return obj1.compareTo(obj2);
                            }
                        });
                        for (Integer regionId : accountGeoMapTemp.get(machineStatus.getAccountId())) {
                            /**与分区的距离*/
                            if (geoRegionMapTemp.get(regionId) == null) {
                                break;
                            }
                            minDistance.put(GeoUtil.getDistance(point, geoRegionMapTemp.get(regionId)), regionId);
                        }
                        GeoreMachine georeMachine = new GeoreMachine();
                        georeMachine.setRegionId(minDistance.values().stream().findFirst().orElse(0));
                        georeMachine.setAccountId(key);
                        georeMachine.setMachineId(machineStatus.getMachineId());
                        if (georeMachineMap.containsKey(machineStatus.getMachineId())) {
                            if (!georeMachineMap.get(machineStatus.getMachineId()).equals(minDistance.values().stream().findFirst().orElse(0))) {
                                georeMachine.setBeforeRegionId(georeMachineMap.get(machineStatus.getMachineId()));
                                georeMachine.setUpdateTime(DateTimeUtil.getNowTime());
                                georeMachinesUpdate.add(georeMachine);
                            }
                        } else {
                            georeMachine.setAddTime(DateTimeUtil.getNowTime());
                            georeMachinesInsert.add(georeMachine);
                        }
                    }
                }
            }

            if (georeMachinesUpdate != null && georeMachinesUpdate.size() > 0) {
                georeMachineService.updateBatch(georeMachinesUpdate);
            }

            if (georeMachinesInsert != null && georeMachinesInsert.size() > 0) {
                georeMachineService.insertBatch(georeMachinesInsert);
            }
        }

        long t2 = System.currentTimeMillis();
        LogUtil.info("分区车辆更新定时任务时间：" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 1/13 * * * ?")
    public void updateParkPointGeo() {
        LogUtil.info("分区站点更新定时任务！");
        long t1 = System.currentTimeMillis();

        /**清除已删除分区站点*/
        List<Integer> parkPointIds = parkPointService.getNotRegionId();
        if (parkPointIds != null && parkPointIds.size() > 0) {
            parkPointService.delRegionId(parkPointIds);
        }

        List<Integer> accountUpdate = georeGionService.getAccountIdUpdate(DateTimeUtil.getNowTimeBefore(-60));

        List<Integer> accountIds = georeGionService.getAccountId();
        accountIds = ListUtil.getSameIntegerList(accountIds, accountUpdate);

        if (accountIds != null && accountIds.size() > 0) {
            /**获取分区站点状态*/
            List<ParkPoint> parkPointList = parkPointService.getByAccountIds(accountIds, DateTimeUtil.getNowTimeBefore(-60));

            if (accountUpdate != null && accountUpdate.size() > 0) {
                parkPointList.addAll(parkPointService.getAccountIds(accountUpdate));
            }

            Map<Integer, List<ParkPoint>> parkPointMap = new HashMap<>();
            for (ParkPoint parkPoint : parkPointList) {
                if (parkPointMap.containsKey(parkPoint.getAccountId())) {
                    parkPointMap.get(parkPoint.getAccountId()).add(parkPoint);
                } else {
                    List<ParkPoint> parkPoints = new LinkedList<>();
                    parkPoints.add(parkPoint);
                    parkPointMap.put(parkPoint.getAccountId(), parkPoints);
                }
            }


            List<Map<String, Object>> parkPointGeo = new LinkedList<>();
            for (Integer key : parkPointMap.keySet()) {
                for (ParkPoint parkPoint : parkPointMap.get(key)) {
                    boolean exist = true;
                    Point point = new Point();
                    point.setX(parkPoint.getLo());
                    point.setY(parkPoint.getLa());
                    List<Integer> regionIdList = dataService.getAccountIdGeore(parkPoint.getAccountId());
                    if (CollUtil.isNotEmpty(regionIdList)) {
                        for (Integer regionId : regionIdList) {
                            /**在区域内的*/
                            if (CollUtil.isNotEmpty(dataService.getGeore(regionId))) {
                                break;
                            }
                            if (GeoUtil.IsPtInPoly(point, dataService.getGeore(regionId))) {
                                exist = false;
                                if (parkPoint.getRegionId() == null || !parkPoint.getRegionId().equals(regionId)) {
                                    Map<String, Object> map = new HashMap<>();
                                    map.put("parkPointId", parkPoint.getParkPointId());
                                    map.put("regionId", regionId);
                                    parkPointGeo.add(map);
                                }
                                break;
                            }
                        }
                    }

                    /**不在所有分区内*/
                    if (exist) {
                        Map<Double, Integer> minDistance = new TreeMap<>(new Comparator<Double>() {
                            public int compare(Double obj1, Double obj2) {
                                return obj1.compareTo(obj2);
                            }
                        });
                        for (Integer regionId : dataService.getAccountIdGeore(parkPoint.getAccountId())) {
                            /**与分区的距离*/
                            minDistance.put(GeoUtil.getDistance(point, dataService.getGeore(regionId)), regionId);
                        }

                        if (parkPoint.getRegionId() == null || !parkPoint.getRegionId().equals(minDistance.values().stream().findFirst().orElse(0))) {
                            Map<String, Object> map = new HashMap<>();
                            map.put("parkPointId", parkPoint.getParkPointId());
                            map.put("regionId", minDistance.values().stream().findFirst().orElse(0));
                            parkPointGeo.add(map);
                        }
                    }
                }
            }

            if (parkPointGeo != null && parkPointGeo.size() > 0) {
                parkPointService.updateBatch(parkPointGeo);
            }
        }

        long t2 = System.currentTimeMillis();
        LogUtil.info("分区站点更新定时任务时间：" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 1/14 * * * ?")
    public void updateProhibitGeo() {
        LogUtil.info("分区禁停区更新定时任务！");
        long t1 = System.currentTimeMillis();

        /**清除已删除分区站点*/
        List<Integer> prohibitAreaIds = prohibitAreaService.getNotRegionId();
        if (prohibitAreaIds != null && prohibitAreaIds.size() > 0) {
            prohibitAreaService.delRegionId(prohibitAreaIds);
        }

        List<Integer> accountUpdate = georeGionService.getAccountIdUpdate(DateTimeUtil.getNowTimeBefore(-60));

        List<Integer> accountIds = georeGionService.getAccountId();
        accountIds = ListUtil.getSameIntegerList(accountIds, accountUpdate);

        if (accountIds != null && accountIds.size() > 0) {
            /**获取分区禁停区状态*/
            List<ProhibitArea> prohibitAreaList = prohibitAreaService.getByAccountIds(accountIds, DateTimeUtil.getNowTimeBefore(-60));

            if (accountUpdate != null && accountUpdate.size() > 0) {
                prohibitAreaList.addAll(prohibitAreaService.getAccountIds(accountUpdate));
            }

            Map<Integer, List<ProhibitArea>> prohibitMap = new HashMap<>();
            for (ProhibitArea prohibitArea : prohibitAreaList) {
                if (prohibitMap.containsKey(prohibitArea.getAccountId())) {
                    prohibitMap.get(prohibitArea.getAccountId()).add(prohibitArea);
                } else {
                    List<ProhibitArea> prohibitAreas = new LinkedList<>();
                    prohibitAreas.add(prohibitArea);
                    prohibitMap.put(prohibitArea.getAccountId(), prohibitAreas);
                }
            }

            List<Map<String, Object>> prohibitGeo = new LinkedList<>();
            for (Integer key : prohibitMap.keySet()) {
                for (ProhibitArea prohibitArea : prohibitMap.get(key)) {
                    boolean exist = true;
                    Point point = new Point();
                    point.setX(prohibitArea.getLo());
                    point.setY(prohibitArea.getLa());
                    for (Integer regionId : dataService.getAccountIdGeore(prohibitArea.getAccountId())) {
                        /**在区域内的*/
                        if (CollUtil.isNotEmpty(dataService.getGeore(regionId))) {
                            break;
                        }
                        if (GeoUtil.IsPtInPoly(point, dataService.getGeore(regionId))) {
                            exist = false;
                            if (prohibitArea.getRegionId() == null || !prohibitArea.getRegionId().equals(regionId)) {
                                Map<String, Object> map = new HashMap<>();
                                map.put("prohibitAreaId", prohibitArea.getProhibitAreaId());
                                map.put("regionId", regionId);
                                prohibitGeo.add(map);
                            }
                            break;
                        }
                    }

                    /**不在所有分区内*/
                    if (exist) {
                        Map<Double, Integer> minDistance = new TreeMap<>(new Comparator<Double>() {
                            public int compare(Double obj1, Double obj2) {
                                return obj1.compareTo(obj2);
                            }
                        });
                        for (Integer regionId : dataService.getAccountIdGeore(prohibitArea.getAccountId())) {
                            /**与分区的距离*/
                            minDistance.put(GeoUtil.getDistance(point, dataService.getGeore(regionId)), regionId);
                        }

                        if (prohibitArea.getRegionId() == null || !prohibitArea.getRegionId().equals(minDistance.values().stream().findFirst().orElse(0))) {
                            Map<String, Object> map = new HashMap<>();
                            map.put("prohibitAreaId", prohibitArea.getProhibitAreaId());
                            map.put("regionId", minDistance.values().stream().findFirst().orElse(0));
                            prohibitGeo.add(map);
                        }
                    }
                }
            }

            if (prohibitGeo != null && prohibitGeo.size() > 0) {
                prohibitAreaService.updateBatch(prohibitGeo);
            }
        }

        long t2 = System.currentTimeMillis();
        LogUtil.info("分区禁停区更新定时任务时间：" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 59 23 28-31 * ?")
    public void foundEvent() {
        LogUtil.info("自动运维大事件定时任务！");
        long t1 = System.currentTimeMillis();
        //每月最后一天执行
        final Calendar c = Calendar.getInstance();
        /**
         * c.get(Calendar.DATE) 当前时间
         * c.getActualMaximum(Calendar.DATE) 本月最后一日
         */
        if (c.get(Calendar.DATE) == c.getActualMaximum(Calendar.DATE)) {
            String startTime = DateTimeUtil.getMothStart();
            String endTime = DateTimeUtil.getMothEnd();
            Integer count = 500;

            List<Map<String, Object>> mapList = machineService.getAccountEvent(startTime, endTime, count);

            if (mapList != null && mapList.size() > 0) {
                String time = DateTimeUtil.getNowTime();
                for (Map<String, Object> map : mapList) {
                    map.put("addTime", time);
                    map.put("level", 1);
                    map.put("title", "增加车辆");
                    map.put("remark", "系統自动添加");
                }
                accountEventService.insertUpdate(mapList);
            }
        }
        long t2 = System.currentTimeMillis();
        LogUtil.info("自动运维大事件定时任务时间：" + (t2 - t1) + "ms");
    }

}
